package com.pb.infra.oth.util;

import com.pb.infra.oth.exception.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

@Data
@Slf4j
public class ValidateRuleFunc {
    public int n = 0;
    public char[] token = new char[61];
    public char[] in = new char[61];
    public List list = new ArrayList();

    public void match(char expected) throws RuleIllegalException {
        if (token[n] == expected) {
            token[++n] = in[n];
        } else {
            throw new RuleIllegalException();
        }
    }

    public double exp() throws RuleIllegalException {
        double temp = 0;
        try {
            temp = term();
            while ((token[n] == '+') || (token[n] == '-')) {
                switch (token[n]) {
                    case '+':
                        match('+');
                        temp += term();
                        break;
                    case '-':
                        match('-');
                        temp -= term();
                        break;
                    default:
                        break;
                }
            }
        } catch (RuleIllegalException e) {
            throw e;
        }
        return temp;
    }

    public double term() throws RuleIllegalException {
        double div;
        double temp = 0;
        try {
            temp = factor();
            while ((token[n] == '*') || (token[n] == '/')) {
                switch (token[n]) {
                    case '*':
                        match('*');
                        temp *= factor();
                        break;
                    case '/':
                        match('/');
                        div = factor();
                        if (div == 0) {
                            throw new RuleIllegalException();
                        }
                        temp /= div;
                        break;
                    default:
                        break;
                }
            }
        } catch (RuleIllegalException e) {
            throw e;
        }
        return temp;
    }

    public double factor() throws RuleIllegalException {
        double temp = 0.0;
        char[] number = new char[61];
        int i = 0;
        try {
            if (token[n] == '(') {
                match('(');
                temp = exp();
                match(')');
            } else if ((token[n] > 47 && token[n] < 58) || token[n] == '.') {
                while ((token[n] > 47 && token[n] < 58) || token[n] == '.') {
                    number[i++] = token[n++];
                    token[n] = in[n];
                }
                number[i] = '\0';
                String tt = new String(number);
                temp = Double.parseDouble(tt.trim());
            } else {
                throw new RuleIllegalException();
            }
        } catch (RuleIllegalException e) {
            throw e;
        }
        return temp;
    }

    public void foolishMethod() throws RuleIllegalException {
        try {
            exp();
        } catch (RuleIllegalException e) {
            throw e;
        }
    }

    public void decompose(String src) throws FuncNumNearException, FuncLeftBracketException, FuncStructException, FuncFuncNearException, FuncParamException, FuncParamStructException, BracketNumException {
        if (src.indexOf('a') == -1) {
            this.list.add(src);
            return;
        }
        List location = new ArrayList();
        StringBuilder overStrBuffer = new StringBuilder();
        for (int i = 0; i < src.length(); i++) {
            if (src.charAt(i) == 'a') {
                if (i != 0 && ((int) src.charAt(i - 1) >= 48 && (int) src.charAt(i - 1) <= 57)) {
                    throw new FuncNumNearException();
                }
                int[] loc = new int[2];
                loc[0] = i;
                i += 2;
                if (i > src.length() - 1 || src.charAt(i) != '(') {
                    throw new FuncLeftBracketException();
                }
                boolean end = false;
                int bracketCount = 1;
                int preComma = i + 1;
                int paramNum = Integer.parseInt(src.substring(i - 1, i));
                int paramCount = 0;
                while (!end) {
                    i++;
                    if (i > src.length() - 1) {
                        throw new BracketNumException();
                    }
                    if (src.charAt(i) == ',' && bracketCount == 1) {
                        paramCount++;
                        String strTmp = src.substring(preComma, i);
                        if (strTmp.trim().equals("")) {
                            throw new FuncStructException();
                        } else {
                            decompose(strTmp);
                        }
                        preComma = i + 1;
                    }
                    if (src.charAt(i) == '(') {
                        bracketCount++;
                    } else if (src.charAt(i) == ')') {
                        bracketCount--;
                        if (bracketCount == 0) {
                            if (i != src.length() - 1 && ((int) src.charAt(i + 1) >= 48 && (int) src.charAt(i + 1) <= 57)) {
                                throw new FuncNumNearException();
                            }
                            if (i != src.length() - 1 && src.charAt(i + 1) == 'a') {
                                throw new FuncFuncNearException();
                            }
                            if (paramCount + 1 != paramNum) {
                                throw new FuncParamException();
                            }
                            String strTmp = src.substring(preComma, i);
                            if (strTmp.trim().equals("")) {
                                throw new FuncParamStructException();
                            } else {
                                decompose(strTmp);
                            }
                            end = true;
                            loc[1] = i;
                            location.add(loc);
                        }
                    }
                }
            }
        }

        int preEnd = 0;
        for (int i = 0; i < location.size(); i++) {
            int[] loc = (int[]) location.get(i);
            if (i == 0) {
                overStrBuffer.append(src, 0, loc[0]);
            } else {
                overStrBuffer.append(src, preEnd + 1, loc[0]);
            }
            overStrBuffer.append("3");
            preEnd = loc[1];
        }
        if (preEnd < src.length() - 1) {
            overStrBuffer.append(src.substring(preEnd + 1));
        }
        this.list.add(overStrBuffer.toString());
    }
}
